#include <zenoui/widgets/GraphicsViewWidget.hpp>
#include <zenoui/widgets/GraphicsItemWidget.hpp>
#include <zenoui/check_gl.hpp>

namespace zenoui {

void GraphicsViewWidget::paint() { // paint children graphics items
    EmptyWidget::paint();
    auto myrect = rect();
    float width = 1.75f;
    float spacing = 100.0f;
    float minstep = 5.0f;
    glm::vec4 color = {0.8f, 0.8f, 0.8f, 0.18f};
    auto xform = transform();
    auto step = xform.scaling * spacing;
    for (int k = 0; k < 3; k++) {
        if (step <= minstep) {
            break;
        }
        color.a *= std::min(std::max(0.0f, (step - minstep) / (2.5f * minstep)), 1.0f);
        if (color.a <= 0.01f) {
            break;
        }
        auto xoff = xform.translation.x - std::floor(xform.translation.x / step) * step;
        auto yoff = xform.translation.y - std::floor(xform.translation.y / step) * step;
        CHECK_GL(glColor4fv(glm::value_ptr(color)));
        CHECK_GL(glLineWidth(width));
        glBegin(GL_LINES);
        for (float
        x = myrect.left() + xoff;
        x <= myrect.right() + xoff;
        x += step
        ) {
            glVertex2f(x, myrect.top());
            glVertex2f(x, myrect.bottom());
        }
        for (float
        y = myrect.top() + yoff;
        y <= myrect.bottom() + yoff;
        y += step
        ) {
            glVertex2f(myrect.left(), y);
            glVertex2f(myrect.right(), y);
        }
        CHECK_GL(glEnd());
        step *= 0.1f;
        width *= 0.5f;
        color.a *= 0.6f;
    }
}

void GraphicsViewWidget::handle(MouseClickEvent *event) {
    if (event->button() == MouseMiddleButton) {
        event->accept(this);
    } else if (event->button() == MouseLeftButton) {
        bool ctrl = event->mods() & ModifierCtrl;
        if (!ctrl) {
            for (auto const &item: m_selected_items)
                if (item) [[likely]] item->m_selected = false;
            m_selected_items.clear();
        }
        event->accept(this);
    }
}

void GraphicsViewWidget::handle(MouseMoveEvent *event) {
    if (event->button() == MouseMiddleButton) {
        auto xform = transform();
        zenox::log_trace("GraphicsViewWidget handling mouse move mouse={}, myoff={}, delta={}",
                         event->pos(), xform.translation, event->delta_pos());
        xform.translation += event->delta_pos();
        set_transform(xform);
        event->accept(this);
    }
}

void GraphicsViewWidget::handle(MouseWheelEvent *event) {
    auto xform = transform();
    zenox::log_trace("GraphicsViewWidget handling mouse wheel mouse={}, myoff={}, delta={}",
                     event->pos(), xform.translation, event->delta_wheel());
    auto pivot = event->pos() - rect().topleft();
    xform.post_translate(-pivot);
    xform.post_scale(std::exp(event->delta_wheel().y * 0.125f));
    xform.post_translate(pivot);
    set_transform(xform);
    event->accept(this);
}

void GraphicsViewWidget::handle(MouseReleaseEvent *event) {
    if (event->button() == MouseMiddleButton) {
        event->accept(this);
    }
}

void GraphicsViewWidget::set_transform(Transform const &transform) {
    modify_shape([&] (Shape &sp) {
        sp.transform = transform;
    });
}

Transform const &GraphicsViewWidget::transform() const {
    return shape().transform;
}

GraphicsViewWidget::GraphicsViewWidget() {
    modify_shape([&] (Shape &sp) {
        sp.layout = AbsoluteLayout;
    });
    m_background_color = {0.05f, 0.1f, 0.15f, 1.0f};
}

GraphicsViewWidget::~GraphicsViewWidget() {
}

}
